﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Objects;
using System.Transactions;
using System.Configuration;
using JeanFish.Data.Configuration;

namespace JeanFish.Data
{
    /// <summary>
    /// 表示通用数据上下文。
    /// </summary>
    /// <typeparam name="TDataContext">数据上下文类型</typeparam>
    public abstract class CommonDataContext<TDataContext>
        where TDataContext : ObjectContext, new()
    {
        /// <summary>
        /// 通过加载配置文件初始化静态通用数据上下文
        /// </summary>
        static CommonDataContext()
        {
            CommonDataSetting setting = ConfigurationManager.GetSection("siteSetting") as CommonDataSetting;
            if (setting == null)
                setting = new CommonDataSetting();
            if (setting.SingletonContext)
            {
                TDataContext db = new TDataContext();
                db.CommandTimeout = db.Connection.ConnectionTimeout;
                db.ContextOptions.ProxyCreationEnabled = false;
                contextSingleton = db;
            }
        }
        /// <summary>
        /// 初始化通用数据上下文
        /// </summary>
        public CommonDataContext()
        {
            if (contextSingleton == null)
            {
                this.context = new TDataContext();
            }
        }
        /// <summary>
        /// 通用数据上下文单体
        /// </summary>
        static TDataContext contextSingleton = null;
        /// <summary>
        /// 非静态数据上下文
        /// </summary>
        private TDataContext context = null;
        /// <summary>
        /// 当前数据上下文
        /// </summary>
        internal TDataContext CurrentContext
        {
            get
            {
                if (contextSingleton == null) return this.context;
                else return contextSingleton;
            }
        }
        /// <summary>
        /// 创建事务范围
        /// </summary>
        /// <returns>通用数据事务接口</returns>
        protected virtual ICommonDataTransaction CreateScope()
        {
            return new DefaultDataContextScope(this.CurrentContext);
        }
        /// <summary>
        /// 表示默认数据上下文事务范围。
        /// </summary>
        private class DefaultDataContextScope:ICommonDataTransaction
        {
            /// <summary>
            /// 表示传入的事务操作的委托
            /// </summary>
            private delegate void DataContextScopeHandler();
            /// <summary>
            /// 传入委托集合
            /// </summary>
            private List<DataContextScopeHandler> operations = new List<DataContextScopeHandler>();
            /// <summary>
            /// 当事务范围完成时发生
            /// </summary>
            private event DataContextScopeHandler ScopeCompleting;
            /// <summary>
            /// 表示数据上下文
            /// </summary>
            TDataContext context;
            /// <summary>
            /// 初始化默认数据上下文事务范围
            /// </summary>
            /// <param name="context"></param>
            internal DefaultDataContextScope(TDataContext context)
            {
                this.context = context;
            }
            /// <summary>
            /// 传入一批事务操作
            /// </summary>
            /// <param name="operation">事务操作调用</param>
            /// <returns>当前实例，实现链式调用</returns>
            public ICommonDataTransaction Batch(Action operation)
            {
                DataContextScopeHandler doNext = new DataContextScopeHandler(operation);
                operations.Add(doNext);
                this.ScopeCompleting += doNext;
                return this;
            }
            /// <summary>
            /// 显示执行已传入的事务操作。
            /// </summary>
            public void Go()
            {
                try
                {
                    using (TransactionScope scope = new TransactionScope())
                    {
                        if (this.ScopeCompleting != null)
                            ScopeCompleting();
                        scope.Complete();
                        context.AcceptAllChanges();
                    }
                }
                catch
                {
                    throw;
                }
                finally
                {
                    this.operations.ForEach(_ => this.ScopeCompleting -= _);
                    this.operations.Clear();
                }
            }
            /// <summary>
            /// 释放资源，会引发执行事务操作
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            /// <summary>
            /// 释放资源
            /// </summary>
            /// <param name="disposing">是否引发执行事务操作</param>
            protected void Dispose(bool disposing)
            {
                if (disposing)
                {
                    Go();
                    this.context = null;
                    this.operations = null;
                }
                ///非托管资源
            }
            /// <summary>
            /// 析构，不会引发执行事务操作
            /// </summary>
            ~DefaultDataContextScope()
            {
                Dispose(false);
            }
        }
    }
}
